package ing.gzq.websocket;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import ing.gzq.model.Message;
import ing.gzq.model.Room;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.io.IOException;
import java.util.Map;

import static ing.gzq.model.Message.*;
import static ing.gzq.websocket.WebSocketUtil.sendMessage;
import static ing.gzq.websocket.WebsocketContainer.*;


@Component
public class WebSocket extends TextWebSocketHandler{

    static Log log = LogFactory.getLog(WebSocket.class);

    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        Map<String, Object> attributes = session.getAttributes();
        String username= getUsername(session);
        String type = getType(session);
        Long roomId = getRoomId(session);
        Room room = null;
        if (isStudent(session)) {
            if (containsRoom(roomId)) {
                room = getRoomById(roomId);
                room.addStudent(username, session);
            } else {
                room = createNewRoomByStudent(roomId,username,session);
            }
        } else if (isTeacher(session)) {
            if (containsRoom(roomId)) {
                room = getRoomById(roomId);
                room.setTeacherId(username);
                room.setTeacherSession(session);
                room.sendToStudents(JSON.toJSONString(INFORM_OPEN));
            } else {
                room = createNewRoomByTeacher(roomId,username,session);
            }
        }
        attributes.put("room",room);
        log.info("user login " + username +"  "+ type+"   "+ roomId);
        System.out.println(username + " connect ");
    }


    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        Room room =getRoom(session);
        String jbStr = message.getPayload();
        log.info("receive message"+"    "+jbStr);
        JSONObject jb;
        try {
            jb = JSON.parseObject(jbStr);
        }catch (JSONException ex){
            sendMessage(session,getErrorMessage("无法解析字符串为jsonObject"));
            return;
        }
        if (checkType(jb,NEW_ICE_CANDIDATE)) {
            room.sendToTarget(jb.getString("target"),jbStr);
        } else if (checkType(jb,VIDEO_OFFER) && isStudent(session)) {
            room.sendToTeacher(jbStr);
        } else if (checkType(jb,VIDEO_ANSWER) && isTeacher(session)) {
            room.sendToStudent(jb.getString("target"), jbStr);
        } else if (checkType(jb,SEND_MESSAGE) ) {
            room.sendToAll(jbStr);
        }
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        String username = getUsername(session);
        sendMessage(session,getErrorMessage("on error"));
        exception.printStackTrace();
        handleLogout(session);
        log.error(exception.getMessage());
        System.err.println(username + " disconnect  error");
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        String username = getUsername(session);

        handleLogout(session);
        session.close();
        System.out.println(username + " disconnect ");
    }

    private void handleLogout(WebSocketSession session) throws IOException {
        String username = getUsername(session);
        Room room = getRoom(session);
        String type = getType(session);

        if ("teacher".equals(type)) {
            room.setTeacherId(null);
            room.setTeacherSession(null);
            room.sendToStudents(JSON.toJSONString(INFORM_CLOSE));
        } else if ("student".equals(type)) {
            room.removeStudent(username);
        }
        log.info("user logout " + username +"   "+ type+"   "+ room);
    }

    private String getErrorMessage(String cause) {
        Message<String> errorMessage = new Message<>();
        errorMessage.setType(ERROR);
        errorMessage.setData(cause);
        return JSON.toJSONString(errorMessage);
    }

    private boolean checkType(JSONObject jb, String type) {
        return type.equals(jb.getString("type"));
    }

    private boolean isStudent(WebSocketSession session){
        return "student".equals(getType(session));
    }

    private boolean isTeacher(WebSocketSession session){
        return "teacher".equals(getType(session));
    }

    private String getType(WebSocketSession session){
        return (String) session.getAttributes().get("type");
    }

    private String getUsername(WebSocketSession session){
        return (String) session.getAttributes().get("username");
    }

    private Long getRoomId(WebSocketSession session) {
        return (Long) session.getAttributes().get("roomId");
    }

    private Room getRoom(WebSocketSession session){
        return (Room)session.getAttributes().get("room");
    }

}
